package com.saer.server.network.red;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

import javax.swing.Timer;

import com.saer.server.network.logica.mensajes.Mensaje;
import com.saer.server.network.logica.mensajes.MensajeDatos;
import com.saer.server.network.logica.mensajes.MensajeFinC;
import com.saer.server.network.logica.mensajes.MensajeIniC;
import com.saer.server.network.logica.mensajes.MensajePing;
import com.saer.server.network.logica.mensajes.MensajePong;
import com.saer.server.network.logica.mensajes.MensajeTexto;

public class ServerKeepAliveSocket {
	private Socket sock;
	private SocketListener sl = null;
	private boolean ka_on;
	private Timer timer;

	// Para la transmision de datos
	private DataInputStream in;
	private DataOutputStream out;

	// El emmarcador
	private Enmarcador marker;
	// El ConectionManager
	private ConectionManager manager;

	// Leer de la configuracion
	// private int id_cap = 1; (este cap)
	// Necesito un generador de nros
	// private int id_msj = 1;
	private int id_org;

	public ServerKeepAliveSocket(Socket s, ConectionManager cm) {
		sock = s;
		manager = cm;
		ka_on = false;

		try {
			in = new DataInputStream(sock.getInputStream());
			out = new DataOutputStream(sock.getOutputStream());
			marker = new Enmarcador(in, out);

			// default: 60 seg de timer
			timer = new Timer(5 * 1000, new ActiveKeepAliveListener());
			timer.setRepeats(true);

			new receptor(this).start();

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void setKeepAlive(boolean ka) {
		ka_on = ka;
		if (ka) { // ka == false
			timer.start();
		} else {
			timer.stop();
		}
	}

	public boolean getKeepAlive() {
		return ka_on;
	}

	private void desconectar() {
		try {
			manager.remover(id_org);
			timer.stop();
			in.close();
			out.close();
			sock.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public synchronized void send(Mensaje m) throws IOException {
		byte[] msj_byte = m.toByte();
		marker.enmarcar(msj_byte);
	}

	public void addListener(SocketListener sl) {
		this.sl = sl;
	}

	private String getTipo(byte[] input) throws IOException {
		String ret = null;
		ByteArrayInputStream bais = new ByteArrayInputStream(input);
		DataInputStream in = new DataInputStream(bais);
		in.readUTF();
		ret = in.readUTF();
		in.close();
		bais.close();

		return ret;
	}

	private class receptor extends Thread {

		ServerKeepAliveSocket papa;

		public receptor(ServerKeepAliveSocket papa) {
			this.papa = papa;
		}

		public void run() {
			String tipo = null;
			try {

				byte[] req;
				while ((req = marker.desenmarcar()) != null) {
					System.out.println("Llego un mensje de: " + req.length + " bytes");
					tipo = getTipo(req);

					if (tipo.equals("DATO")) {
						MensajeDatos mdc = MensajeDatos.fromByte(req);
						sl.agregar_mensaje(mdc);
					} else if (tipo.equals("INIC")) {
						MensajeIniC m = MensajeIniC.fromByte(req);
						id_org = m.getIDorigen();

						if (!manager.existe(id_org)) {
							manager.registrar(id_org, this.papa);
						}
					}

					else if (tipo.equals("TXTO")) {
						MensajeTexto mtexto = MensajeTexto.fromByte(req);
						System.out.println("Recibi un mensaje de texto, viene del hospital?");
					} else if (tipo.equals("PING")) {
						MensajePing mping = MensajePing.fromByte(req);
						System.out.println("Recibi PING");

						MensajePong m = new MensajePong();
						m.setIDmensaje(1); // Usar datos de mping para validar?
						m.setIDorigen(1);

						send(m);
					} else if (tipo.equals("PONG")) {
						MensajePong mpong = MensajePong.fromByte(req);
						System.out
								.println("Recibi pong, la conexion esta viva =)");
					}

					else if (tipo.equals("FINC")) {
						MensajeFinC mfinc = MensajeFinC.fromByte(req);

						break;
					}

				} // Fin while

			} catch (IOException ioe) {
				System.out.println("El cliente se desconecto");
				System.err.println("Error handling client: " + ioe.getMessage());
			} catch (MsjNotForMeException e) {
				e.printStackTrace();
			} finally {
				System.out.println("Comunicacion terminada");
				desconectar();
			}

		}

	}

	private class ActiveKeepAliveListener implements ActionListener {
		public void actionPerformed(ActionEvent arg0) {
			try {
				send(new MensajePing());
				System.out.println("Ping enviado");
			} catch (IOException e) {
				System.err.println("Se perdio la comunicacion con la Chacra");
				desconectar();
			}
		}
	}

}
